﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using SDCloudSolution.SDCloud.BusinessLayer.Model.Interfaces;
using SDCloudSolution.SDCloud.Entities.Models;
using SDCloudSolution.SDCloud.Web.Infrastructure.Interfaces;
using SDCloudSolution.SDCloud.Web.Models.Model;

namespace SDCloudSolution.SDCloud.Web.Infrastructure
{
    public class ModelStatisticsViewModelProvider : IModelStatisticsViewModelProvider
    {
        private readonly IUserIdentityProvider _identityProvider;
        private readonly IDataSizeFormatter _dataSizeFormatter;
        private readonly IModelComponent _modelComponent;
        private readonly IModelStatisticsComponent _modelStatisticsComponent;

        public ModelStatisticsViewModelProvider(
            IUserIdentityProvider identityProvider, 
            IDataSizeFormatter dataSizeFormatter,
            IModelComponent modelComponent,
            IModelStatisticsComponent modelStatisticsComponent)
        {
            _identityProvider = identityProvider;
            _dataSizeFormatter = dataSizeFormatter;
            _modelComponent = modelComponent;
            _modelStatisticsComponent = modelStatisticsComponent;
        }

        public async Task<ModelStatisticsViewModel> GetModelStatisticsForModelAsync(int modelId)
        {
            if (modelId <= 0)
            {
                return null;
            }

            var model = await _modelComponent.GetModelByIdAsync(modelId);
            if (model == null)
            {
                return null;
            }

            if (model.UserId != _identityProvider.Current.UserId)
            {
                throw new UnauthorizedAccessException();
            }

            var modelStatistics = await _modelStatisticsComponent.GetModelExecutionStatisticsByModelIdAsync(modelId);
            if (modelStatistics == null)
            {
                return null;
            }

            return ConvertToViewModel(modelStatistics);
        }

        public async Task<ModelStatisticsViewModel> GetModelStatisticsForPublicModelAsync(int publicModelId)
        {
            if (publicModelId <= 0)
            {
                return null;
            }

            var models = await _modelComponent.FindAllModelsRelatedToPublicModel(publicModelId);

            return await GetAggregatedModelStatisticsForModels(models);
        }

        public async Task<ModelStatisticsViewModel> GetModelStatisticsForUserAsync()
        {
            var models = await _modelComponent.FindAllModelsForUser(_identityProvider.Current.UserId);

            return await GetAggregatedModelStatisticsForModels(models);
        }

        private async Task<ModelStatisticsViewModel> GetAggregatedModelStatisticsForModels(IEnumerable<ModelEntity> models)
        {
            var modelIds = models.Select(model => model.Id);

            var modelStatistics = await _modelStatisticsComponent.GetModelExecutionStatisticsByModelIdsAsync(modelIds);
            var aggregatedStatistics = await _modelStatisticsComponent.GetAggregatedModelStatisticsAsync(modelStatistics);

            if (aggregatedStatistics == null)
            {
                return null;
            }

            return ConvertToViewModel(aggregatedStatistics);
        }

        public ModelStatisticsViewModel ConvertToViewModel(ModelStatisticsEntity entity)
        {
            return new ModelStatisticsViewModel
            {
                TotalSuccessExecutionCount = entity.TotalSuccessRunCount,
                TotalFailedExecutionCount = entity.TotalFailedRunCount,
                // TODO Use datetime converter
                MaxExecutionTimeText = entity.MaxExecutionTimeInMilliseconds + " ms",
                MinExecutionTimeText = entity.MinExecutionTimeInMilliseconds + " ms",
                AverageExecutionTimeText = entity.AvgExecutionTimeInMilliseconds + " ms",
                MinDataSizeUsageText = _dataSizeFormatter.ConvertBytesToUserFriendlyFormat(entity.MinDataSizeInBytes),
                MaxDataSizeUsageText = _dataSizeFormatter.ConvertBytesToUserFriendlyFormat(entity.MaxDataSizeInBytes),
                AverageDataSizeUsageText = _dataSizeFormatter.ConvertBytesToUserFriendlyFormat(entity.AvgDataSizeInBytes)
            };
        }

        
    }
}